
/*
 * Hlpay-Plus aggregate payment system. Copyright
 * (c) 2022-2023 Hlpay Team Copyright has the right of final interpretation.
 */

package com.hlkj.pay.app.adminuser.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.pojo.LocalRequest;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.adminuser.IRoleAppService;
import com.hlkj.pay.common.AdminUserResultCode;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.dto.admin.RoleDto;
import com.hlkj.pay.dto.admin.RoleQueryDto;
import com.hlkj.pay.enums.AdminUserEnum;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.infrastructure.model.admin.PermissionDO;
import com.hlkj.pay.infrastructure.model.admin.RoleDO;
import com.hlkj.pay.infrastructure.model.admin.RolePermissionMappingDO;
import com.hlkj.pay.service.admin.IAdminUserService;
import com.hlkj.pay.service.admin.IPermissionService;
import com.hlkj.pay.service.admin.IRoleService;
import com.hlkj.pay.service.common.IBusinessLogService;
import com.hlkj.pay.vo.admin.req.role.RoleAddReq;
import com.hlkj.pay.vo.admin.req.role.RolePermissionReq;
import com.hlkj.pay.vo.admin.req.role.RoleUpdateReq;
import com.hlkj.pay.vo.admin.resp.role.RoleDetailResp;

import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/09/06 10:37
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RoleAppServiceImpl implements IRoleAppService {

    private final IRoleService roleService;

    private final IBusinessLogService businessLogService;

    private final IPermissionService permissionService;

    private final IAdminUserService userService;
    @Value("${merchant.role.register:R0000002}")
    private String merchantRoleRegister;
    
    @Value("${merchant.role.root:R0000003}")
    private String merchantRoleRoot;
    @Override
    public CommonResult<RoleDetailResp> queryRoleDetail(String roleCode) {
        try {
            RoleDto roleDto = roleService.queryRoleDetail(roleCode);
            if (roleDto == null) {
                return CommonResult.error(AdminUserResultCode.ROLE_DOES_NOT_EXIST);
            }
            RoleDetailResp roleDetailResp = new RoleDetailResp();
            BeanUtils.copyProperties(roleDto, roleDetailResp);
            // permissionList
            // List<PermissionDO> permissionList = permissionService.queryAllPermission();

            // if (CollectionUtils.isEmpty(permissionList)) {
            // return CommonResult.success(roleDetailResp);
            // }
            // roleDetailResp.setPermissionList(PermissionCoverUtils
            // .permissionMenuList(permissionList, roleDto.getSuperAdminFlag(),
            // roleDto.getRolePermissions()));
            List<RolePermissionMappingDO> rolePermissions = roleDto.getRolePermissions();
            if (!CollectionUtils.isEmpty(rolePermissions)) {
                List<String> menuCodes = rolePermissions.stream().map(rolePermissionMappingDO -> rolePermissionMappingDO.getPermissionCode()).collect(Collectors.toList());
                roleDetailResp.setMenuCodes(menuCodes);
            }
            return CommonResult.success(roleDetailResp);
        }
        catch (Exception e) {
            log.error("addRole error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public Boolean isAdmin(List<String> roleCodes,Integer sysType) {
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setCodeList(roleCodes);
        List<RoleDO> roleList = roleService.queryRoleList(roleQueryDto);
        if(CollUtil.isNotEmpty(roleList)){
            for(RoleDO role:roleList){
                // 超级管理员
                if(true == role.getSuperAdminFlag()){
                    return true;
                }else{
                    // 其他管理员
                    if(role.getSysType() == sysType && 1 == role.getDefaultRole()){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @Override
    public CommonResult<String> addRole(RoleAddReq roleAddReq) {
        log.info("addRole roleAddReq:{}", JsonUtils.toJsonString(roleAddReq));
        try {
            if (roleAddReq.getSuperAdminFlag() == null) {
                roleAddReq.setSuperAdminFlag(Boolean.FALSE);
            }
            // 角色数据验证
            RoleDO beforeRole = roleService.queryRoleByName(roleAddReq.getName());
            if (beforeRole != null) {
                return CommonResult.error(AdminUserResultCode.ROLE_DOES_EXIST);
            }
            if (roleAddReq.getSuperAdminFlag()) {
                RoleQueryDto roleQueryDto = new RoleQueryDto();
                roleQueryDto.setSn(roleQueryDto.getSn());
                roleQueryDto.setSuperAdminFlag(roleAddReq.getSuperAdminFlag());
                List<RoleDO> roleList = roleService.queryRoleList(roleQueryDto);
                if (!CollectionUtils.isEmpty(roleList)) {
                    return CommonResult.error(AdminUserResultCode.ROLE_ADMIN_DOES_EXIST);
                }
            }

            RoleDO roleDO = new RoleDO();
            roleDO.setName(roleAddReq.getName());
            roleDO.setDescription(roleAddReq.getDescription());
            roleDO.setSuperAdminFlag(roleAddReq.getSuperAdminFlag());
            LocalRequest localUserRequest = LocalContext.get();
            roleDO.setSysType(localUserRequest.getSysType());
            roleDO.setSn(localUserRequest.getSn());
            String roleCode = roleService.addRole(roleDO);
            return CommonResult.success(roleCode);
        }
        catch (Exception e) {
            log.error("addRole error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> updateRole(RoleUpdateReq roleUpdateReq) {
        log.info("updateRole roleUpdateReq:{}", JsonUtils.toJsonString(roleUpdateReq));
        try {
            if (roleUpdateReq.getSuperAdminFlag() == null) {
                roleUpdateReq.setSuperAdminFlag(Boolean.FALSE);
            }
            // 角色数据验证
            RoleDto beforeRole = roleService.queryRoleDto(roleUpdateReq.getCode());
            if (beforeRole == null) {
                return CommonResult.error(AdminUserResultCode.ROLE_DOES_NOT_EXIST);
            }
            if (roleUpdateReq.getSuperAdminFlag()) {
                RoleQueryDto roleQueryDto = new RoleQueryDto();
                roleQueryDto.setSn(roleQueryDto.getSn());
                roleQueryDto.setSuperAdminFlag(roleUpdateReq.getSuperAdminFlag());
                List<RoleDO> roleList = roleService.queryRoleList(roleQueryDto);
                if (!CollectionUtils.isEmpty(roleList)) {
                    RoleDO roleDO = roleList.get(0);
                    if (!roleDO.getCode().equals(roleUpdateReq.getCode())) {
                        return CommonResult.error(AdminUserResultCode.ROLE_ADMIN_DOES_EXIST);
                    }
                }
            }
            RoleDO roleRespByName = roleService.queryRoleByName(roleUpdateReq.getName());
            if (roleRespByName != null && !roleRespByName.getCode().equals(beforeRole.getCode())) {
                return CommonResult.error(AdminUserResultCode.ROLE_DOES_EXIST);
            }
            RoleDO roleDO = new RoleDO();
            roleDO.setName(roleUpdateReq.getName());
            roleDO.setDescription(roleUpdateReq.getDescription());
            roleDO.setSuperAdminFlag(roleUpdateReq.getSuperAdminFlag());
            roleDO.setId(beforeRole.getId());
            // updateRole
            roleService.updateRole(roleDO);
            // log
            RoleDto afterRole = new RoleDto();
            afterRole.setName(roleUpdateReq.getName());
            afterRole.setDescription(roleUpdateReq.getDescription());
            businessChangeLog(beforeRole, afterRole);
            return CommonResult.success(null);
        }
        catch (Exception e) {
            log.error("updateRole error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> deleteRole(String roleCode) {
        log.info("deleteRole roleCode:{}", roleCode);
        try {
            if(!StringUtils.hasText(roleCode)){
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            if(merchantRoleRegister.equals(roleCode)||merchantRoleRoot.equals(roleCode)){
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            // 角色数据验证
            RoleDto beforeRole = roleService.queryRoleDto(roleCode);
            if (beforeRole == null) {
                return CommonResult.error(AdminUserResultCode.ROLE_DEFAULT_DOES_NOT_DELETE);
            }
            // updateRole
            roleService.delRole(roleCode);
            // 角色对应的用户关联数据更新
            userService.roleChangeUser(roleCode, Boolean.TRUE);
            // log
            RoleDto afterRole = new RoleDto();
            BeanUtils.copyProperties(beforeRole, afterRole);
            afterRole.setDeleteFlag(Boolean.TRUE);
            businessChangeLog(beforeRole, afterRole);
            return CommonResult.success(null);
        }
        catch (Exception e) {
            log.error("deleteRole error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> assignRolePermission(RolePermissionReq rolePermissionReq) {
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("queryRoleDto");
            // 角色数据验证
            RoleDto beforeRole = roleService.queryRoleDto(rolePermissionReq.getCode());
            stopWatch.stop();
            if (beforeRole == null) {
                return CommonResult.error(AdminUserResultCode.ROLE_DOES_NOT_EXIST);
            }
            stopWatch.start("coverRolePermissions");
            List<PermissionDO> permissionList = coverRolePermissions(rolePermissionReq.getPermissionCodes(),rolePermissionReq.getSysType());
            stopWatch.stop();
            stopWatch.start("updateRole");
            // updateRole
            roleService.updateRolePermission(rolePermissionReq.getCode(), permissionList);
            stopWatch.stop();
            stopWatch.start("roleChangeUser");
            // 角色对应的用户关联数据更新
            userService.roleChangeUser(rolePermissionReq.getCode(), Boolean.FALSE);
            stopWatch.stop();
            stopWatch.start("businessChangeLog");
            // log
            RoleDto afterRole = new RoleDto();
            BeanUtils.copyProperties(beforeRole, afterRole);
            List<RolePermissionMappingDO> rolePermissions = new ArrayList<>();
            permissionList.stream().forEach(rolePermission -> {
                RolePermissionMappingDO rolePermissionMappingDO = new RolePermissionMappingDO();
                rolePermissionMappingDO.setRoleCode(rolePermissionReq.getCode());
                rolePermissionMappingDO.setPermissionCode(rolePermission.getCode());
                rolePermissions.add(rolePermissionMappingDO);
            });
            afterRole.setRolePermissions(rolePermissions);
            businessChangeLog(beforeRole, afterRole);
            stopWatch.stop();
            if (log.isDebugEnabled()) {
                log.debug("assignRolePermission total:{},assignRolePermission:{}", stopWatch.getTotalTimeMillis(), stopWatch.prettyPrint());
            }
            return CommonResult.success(null);
        }
        catch (Exception e) {
            log.error("assignRolePermission error:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    /**
     * rolePermissions
     * 
     * @param permissionCodes
     * @return
     */
    List<PermissionDO> coverRolePermissions(List<String> permissionCodes,Integer sysType) {
        List<PermissionDO> permissionList = permissionService.queryAllPermission(sysType);
        return permissionList.stream().filter(permissionDO -> permissionCodes.contains(permissionDO.getCode())).collect(Collectors.toList());
    }

    String permissionActionTypeKey(String parentCode) {
        return parentCode;
    }

    /**
     * log object
     * 
     * @param beforeRole
     * @param afterRole
     * @return
     */
    void businessChangeLog(RoleDto beforeRole, RoleDto afterRole) {
        businessLogService.addBusinessChangeLog(beforeRole.getCode(), AdminUserEnum.CHANGE_LOG_TYPE.ROLE.getCode(), CommonEnum.CHANGE_LOG_MODEL_TYPE.ADMIN, beforeRole,
                afterRole);
    }
}
